using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace TripleMatch
{
    public class ResManager : MonoBehaviour
    {
        private static ResManager s;
        public static ResManager S
        {
            get
            {
                return s;
            }
        }

        private void Awake()
        {
            s = this;
        }

        private Dictionary<string, AssetBundle> assetBundles = new Dictionary<string, AssetBundle>();
        private Dictionary<string, string> abNameToResName = new Dictionary<string, string>();
        private List<ABCreateRequestGroup> allABCreateRequests = new List<ABCreateRequestGroup>();

        List<string> allAssetBundlesWaitingForLoad = null;
        int assetBundleLoadIndex = 0;
        LoadABAsyncCompleted allAssetBundleLoaded;

        private class ABCreateRequestGroup
        {
            public AssetBundleCreateRequest request;
            public string abName;
            public LoadABAsyncCompleted completed;
        }

        public delegate void LoadABAsyncCompleted();

        public AssetBundle GetAssetBundle(string name)
        {
            AssetBundle ab;
            if (!assetBundles.TryGetValue(name, out ab))
            {
                PreloadAssetBundle(name);
            }
            if (!assetBundles.TryGetValue(name, out ab))
            {
                return null;
            }
            return ab;
        }

        /// <summary>
        /// 卸载AssetBundle
        /// </summary>
        /// <param name="name">ab名</param>
        public void UnloadAssetBundle(string name)
        {
            AssetBundle ab;
            if (assetBundles.TryGetValue(name, out ab))
            {
                ab.Unload(true);
                assetBundles.Remove(name);
            }
        }

        public T LoadAsset<T>(string abName, string assetName, string resourcesPath = null) where T : Object
        {
            T result = null;
            bool loadFromResources = false;
#if UNITY_EDITOR
            if (resourcesPath != null)
            {
                loadFromResources = true;
            }
#endif
            if (loadFromResources)
            {
                Resources.UnloadUnusedAssets();
                result = Resources.Load<T>((resourcesPath == "") ? assetName : (resourcesPath + "/" + assetName));
            }
            else
            {
                AssetBundle ab = null;
                if (!assetBundles.TryGetValue(abName, out ab))
                {
                    //ab = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, abName));
                    ab = AesStream.AssetBundleDecryption(Path.Combine(Application.streamingAssetsPath, abName), abName, "datas");
                    if (ab)
                    {
                        assetBundles[abName] = ab;
                    }
                }
                if (ab)
                {
                    result = ab.LoadAsset<T>(assetName);
                }
            }

            return result;
        }

        public void PreloadAssetBundle(string abName)
        {
            AssetBundle ab = null;
            if (!assetBundles.TryGetValue(abName, out ab))
            {
                ab = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, abName));
                if (ab)
                {
                    assetBundles[abName] = ab;
                }
            }
        }

        public void PreloadMutipleAssetBundles(List<string> abNames)
        {
            foreach (var abName in abNames)
            {
                PreloadAssetBundle(abName);
            }
        }

        public void PreloadAssetBundleAsync(string abName, LoadABAsyncCompleted completed)
        {
            AssetBundle ab = null;
            if (!assetBundles.TryGetValue(abName, out ab))
            {
                var request = AssetBundle.LoadFromFileAsync(Path.Combine(Application.streamingAssetsPath, abName));
                //add by dylan load ab proiority 100  
                request.priority = 100;
                request.completed += PreloadAssetBundleFinished;
                ABCreateRequestGroup group = new ABCreateRequestGroup();
                group.request = request;
                group.abName = abName;
                group.completed = completed;
                allABCreateRequests.Add(group);
            }
            else
            {
                completed();
            }
        }

        public void PreloadMutipleAssetBundlesAsync(List<string> abNames, LoadABAsyncCompleted completed)
        {
            allAssetBundlesWaitingForLoad = abNames;
            assetBundleLoadIndex = 0;
            allAssetBundleLoaded = completed;
            DoPreloadAssetBundle();
        }

        public void CancelPreloadMutipleAssetBundlesAsync()
        {
            allAssetBundlesWaitingForLoad = null;
            assetBundleLoadIndex = 0;
            allAssetBundleLoaded = null;
        }

        private void PreloadAssetBundleFinished<AsyncOperation>(AsyncOperation req)
        {
            AssetBundleCreateRequest request = req as AssetBundleCreateRequest;
            for (int i = 0; i != allABCreateRequests.Count;)
            {
                var group = allABCreateRequests[i];
                if (group.request.Equals(request))
                {
                    var ab = request.assetBundle;
                    assetBundles[group.abName] = ab;
                    var completed = group.completed;
                    allABCreateRequests.RemoveAt(i);
                    completed();
                    break;
                }
                else
                {
                    ++i;
                }
            }
        }

        private void DoPreloadAssetBundle()
        {
            if (allAssetBundlesWaitingForLoad == null)
                return;

            if (assetBundleLoadIndex >= allAssetBundlesWaitingForLoad.Count && allAssetBundleLoaded != null)
            {
                allAssetBundleLoaded();
                return;
            }
            else
            {
                int oldIndex = assetBundleLoadIndex;
                assetBundleLoadIndex++;
                PreloadAssetBundleAsync(allAssetBundlesWaitingForLoad[oldIndex], () => {
                    DoPreloadAssetBundle();
                });
            }
        }
    }
}
